package com.zzyl.nursing.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.List;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.CodeGenerator;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.*;
import com.zzyl.nursing.mapper.*;
import com.zzyl.nursing.vo.CheckInConfigVo;
import com.zzyl.nursing.vo.CheckInDetailVo;
import com.zzyl.nursing.vo.CheckInElderVo;
import com.zzyl.nursing.vo.ElderFamilyVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.service.ICheckInService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;

/**
 * 入住Service业务层处理
 *
 * @author zhaoyiyang
 * @date 2025-07-23
 */
@Service
public class CheckInServiceImpl extends ServiceImpl<CheckInMapper, CheckIn> implements ICheckInService
{
    @Autowired
    private CheckInMapper checkInMapper;
    @Autowired
    private ElderMapper elderMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private CheckInConfigMapper checkInConfigMapper;
    @Autowired
    private BedMapper bedMapper;

    /**
     * 查询入住
     *
     * @param id 入住主键
     * @return 入住
     */
    @Override
    public CheckIn selectCheckInById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询入住列表
     *
     * @param checkIn 入住
     * @return 入住
     */
    @Override
    public List<CheckIn> selectCheckInList(CheckIn checkIn)
    {
        return checkInMapper.selectCheckInList(checkIn);
    }

    /**
     * 新增入住
     *
     * @param checkIn 入住
     * @return 结果
     */
    @Override
    public int insertCheckIn(CheckIn checkIn)
    {
        return save(checkIn) ? 1 : 0;
    }

    /**
     * 修改入住
     *
     * @param checkIn 入住
     * @return 结果
     */
    @Override
    public int updateCheckIn(CheckIn checkIn)
    {
        return updateById(checkIn) ? 1 : 0;
    }

    /**
     * 批量删除入住
     *
     * @param ids 需要删除的入住主键
     * @return 结果
     */
    @Override
    public int deleteCheckInByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除入住信息
     *
     * @param id 入住主键
     * @return 结果
     */
    @Override
    public int deleteCheckInById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }
    @Transactional
    @Override
    public void apply(CheckInApplyDto dto) {
        // 判断老人是否已经入住
        // 通过身份证号查询老人
//        拿到老人的身份证号
        String idCardNo = dto.getCheckInElderDto().getIdCardNo();
//        查询老人是否已入住
        LambdaQueryWrapper<CheckIn> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CheckIn::getIdCardNo, idCardNo);
        CheckIn checkInMsg = checkInMapper.selectOne(wrapper);
        if(ObjectUtils.isNotEmpty(checkInMsg)) {
            throw new BaseException("老人已入住");
        }
        else{
            // 更新床位的状态  已入住
            Bed bed = updateBedStatus(dto);
            // 保存或更新老人数据
            Elder elder = saveOrUpdateElder(dto, bed);
            // 生成合同编号
            String htNumber ="HT"+CodeGenerator.generateContractNumber();
            // 新增签约办理
            insertContract(dto,htNumber,elder);
            // 新增入住信息
            CheckIn checkIn = saveCheckIn(dto, elder, bed);
            // 新增入住配置信息
            saveCheckInConfig(checkIn.getId(),dto);
        }

    }

    private void saveCheckInConfig(Long checkInId, CheckInApplyDto dto) {
        CheckInConfig checkInConfig = new CheckInConfig();
        BeanUtils.copyProperties(dto.getCheckInConfigDto(), checkInConfig);
        checkInConfig.setCheckInId(checkInId);
        checkInConfigMapper.insert(checkInConfig);
    }

    private void insertContract(CheckInApplyDto dto, String htNumber, Elder elder) {
        Contract contract = new Contract();
        CheckInContractDto checkInContractDto = dto.getCheckInContractDto();
        BeanUtils.copyProperties(checkInContractDto,contract);
        contract.setContractNumber(htNumber);
        contract.setElderId(Integer.valueOf(elder.getId()+""));
        contract.setElderName(elder.getName());
//        签约时间的判断:如果签约时间小于等于当前时间,则合同生效中
        LocalDateTime checkInStartTime = dto.getCheckInConfigDto().getStartDate();
        LocalDateTime checkInEndTime = dto.getCheckInConfigDto().getEndDate();
        Integer status = checkInStartTime.isBefore(LocalDateTime.now()) ? 1 : 0;
        contract.setStatus(status+"");
        contract.setStartDate(checkInStartTime);
        contract.setEndDate(checkInEndTime);
        contractMapper.insert(contract);
    }


    private Elder saveOrUpdateElder(CheckInApplyDto dto, Bed bed) {
        CheckInElderDto checkInElderDto = dto.getCheckInElderDto();
        Elder elder = new Elder();
        BeanUtils.copyProperties(checkInElderDto, elder);
        elder.setBedId(bed.getId());
        elder.setBedNumber(bed.getBedNumber());
        LambdaQueryWrapper<Elder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Elder::getIdCardNo, elder.getIdCardNo());
        if (ObjectUtils.isEmpty(elderMapper.selectOne(wrapper))) {
//            新增
            elderMapper.insert(elder);
        } else {
//            修改
            elderMapper.updateById(elder);
        }
        return elder;

    }

    private Bed updateBedStatus(CheckInApplyDto dto) {
//        拿到入职配置
        CheckInConfigDto checkInConfigDto = dto.getCheckInConfigDto();
//        拿到床位id
        Long bedId = checkInConfigDto.getBedId();
//        根据床位id查询床位信息
        Bed bed = bedMapper.selectBedById(bedId);
//        更新床位的状态
        LambdaUpdateWrapper<CheckIn> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CheckIn::getId, bedId)
                .set(CheckIn::getStatus, 1);
        update(wrapper);
        return bed;
    }

    private CheckIn saveCheckIn(CheckInApplyDto dto, Elder elder, Bed bed) {
        CheckIn checkIn = new CheckIn();
        checkIn.setElderId(elder.getId());
        checkIn.setElderName(elder.getName());
        checkIn.setIdCardNo(elder.getIdCardNo());
        checkIn.setNursingLevelName(dto.getCheckInConfigDto().getNursingLevelName());
        checkIn.setStartDate(dto.getCheckInConfigDto().getStartDate());
        checkIn.setEndDate(dto.getCheckInConfigDto().getEndDate());
        checkIn.setBedNumber(elder.getBedNumber());
        checkIn.setRemark(JSON.toJSONString(dto.getElderFamilyDtoList()));
        checkIn.setStatus(Long.valueOf(0));
        checkInMapper.insert(checkIn);
        return checkIn;
    }

    @Override
    public CheckInDetailVo detail(Long id) {
    /*
    * 查询入住详情总的也是分为四部分
    * 拿到入住的信息->查询老人的信息->查询合同->查询入住配置->拿到家属列表
    * 最后封装成VO进行返回
    * */
//        创建返回给前端的对象
        CheckInDetailVo checkInDetailVo = new CheckInDetailVo();
//        查询入住信息
        CheckIn elderCheckIn = getElderCheckIn(id);
        Long elderId = elderCheckIn.getElderId();
//        根据elderId查询老人信息
        CheckInElderVo elder = getElder(elderId);
        checkInDetailVo.setCheckInElderVo(elder);
//        查询老人家属的信息
        List<ElderFamilyVo> elderFamily = getElderFamily(elderId);
        checkInDetailVo.setElderFamilyVoList(elderFamily);
//        查询合同的信息
        Contract elderContract = getElderContract(elderId);
        checkInDetailVo.setContract(elderContract);

//        查询入住配置的信息
        CheckInConfigVo elderCheckInConfig = getElderCheckInConfig(elderCheckIn);
        checkInDetailVo.setCheckInConfigVo(elderCheckInConfig);
        return checkInDetailVo;
    }

    private CheckIn getElderCheckIn(Long id) {
        LambdaQueryWrapper<CheckIn> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CheckIn::getId, id);
        CheckIn checkIn = checkInMapper.selectOne(wrapper);
        return checkIn;
    }

    private CheckInConfigVo getElderCheckInConfig(CheckIn elderCheckIn) {
        CheckInConfigVo checkInConfigVo = new CheckInConfigVo();
        LambdaQueryWrapper<CheckInConfig> wrapper = new LambdaQueryWrapper();
        wrapper.eq(CheckInConfig::getCheckInId, elderCheckIn.getId());
//        拿到老人入住配置信息
        CheckInConfig checkInConfig = checkInConfigMapper.selectOne(wrapper);
//        复制入住信息
        BeanUtils.copyProperties(checkInConfig, checkInConfigVo);
//        拿到入住开始时间,入住结束时间,以及入住床位,封装并返回
        LocalDateTime feeStartDate = checkInConfig.getFeeStartDate();
        LocalDateTime feeEndDate = checkInConfig.getFeeEndDate();
        String bedNumber = elderCheckIn.getBedNumber();
        checkInConfigVo.setStartDate(feeStartDate);
        checkInConfigVo.setEndDate(feeEndDate);
        checkInConfigVo.setBedNumber(bedNumber);
        return checkInConfigVo;

    }

    private Contract getElderContract(Long elderId) {
//        根据id查询老人的合同
        LambdaQueryWrapper<Contract> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Contract::getElderId,elderId);
        Contract contract = contractMapper.selectOne(wrapper);
        return contract;
    }

    private List<ElderFamilyVo> getElderFamily(Long elderId) {
        LambdaQueryWrapper<CheckIn> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CheckIn::getElderId, elderId);
//        查询老人的对应信息
        CheckIn checkIn = checkInMapper.selectOne(wrapper);
//        拿到老人备注信息中的家属信息
        String family = checkIn.getRemark();
//        将得到的数据进行转换
        List<ElderFamilyVo> elderFamilyVoList = JSON.parseArray(family, ElderFamilyVo.class);
//        返回得到的家属数据
        return elderFamilyVoList;
    }

    private CheckInElderVo getElder(Long elderId) {
        CheckInElderVo checkInElderVo = new CheckInElderVo();
        LambdaQueryWrapper<Elder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Elder::getId, elderId);
        Elder elder = elderMapper.selectOne(wrapper);
        BeanUtils.copyProperties(elder, checkInElderVo);
/*
        由于我们的老人信息中没有年龄
        所以我们需要通过老人的出生年月日来算出老人的年龄进行封装并返回
*/
//        拿到老人的出生年月日
        String birthday = elder.getBirthday();
//        与当前日期做减法
        Period period = Period.between(LocalDate.parse(birthday), LocalDate.now());
//        得到老人的年龄
        int age = period.getYears();
//        封装
        checkInElderVo.setAge(age);
        return checkInElderVo;
    }
}
